	Editor.Draggers.Connector = function () {
		var inix;
		var iniy;
		var dx;
		var dy;
		var shape;
		var impl;
		var isActive;
		var figConnector;
		var figLine;
		return {
			init: function (s) {
				shape = s;
				impl = shape.getImplementation();
				isActive = false;
			},
			mouseover: function () {
				if (!Editor.Util.isDragging()) {
					figConnector.attr(Editor.CONFIG.VISIBLE_ATTR);
				}
			},
			mouseout: function () {
				if (!Editor.Util.isDragging()) {
					figConnector.attr(Editor.CONFIG.INVISIBLE_ATTR);
				}
			},
			remove: function () {
				figConnector.remove();
				delete figConnector;
			},
			draw: function () {
				figConnector = Editor.STATE.CANVAS.circle(0, 0, Editor.CONFIG.FIGCONNECTOR_RADIUS).attr(Editor.CONFIG.FIGCONNECTOR_ATTR);
				figConnector.translate(shape.getX(), shape.getY());
				figConnector.mouseover(impl.getDraggerConnector().mouseover);
				figConnector.mouseout(impl.getDraggerConnector().mouseout);
				figConnector.mousedown(impl.getDraggerConnector().mousedown);
				figConnector.toFront();
			},
			redraw: function () {
				if (!figConnector) {
					this.draw();
				}
				//var x = shape.getX() - Editor.CONFIG.FIGCONNECTOR_RADIUS;
				//var y = shape.getY() - Editor.CONFIG.FIGCONNECTOR_RADIUS;
				//figConnector.translate(x, y);
			},
			mousedown: function (e) {
				if (!Editor.Util.isDragging()) {
					var offsetY = $(window).scrollTop();
					var offsetX = $(window).scrollLeft();

					var pos = $("#canvas").position();
					dx = e.clientX - pos.left + offsetX;
					dy = e.clientY - pos.top + offsetY;
					inix = dx;
					iniy = dy;

					figLine = Editor.STATE.CANVAS.path(["M", dx, dy, "L", dx, dy].join(",")).attr(Editor.CONFIG.CONNECTORRESIZE_ATTR);
					Editor.STATE.DRAGGER = impl.getDraggerConnector();

					Editor.STATE.BACKGROUNDTEMP=Editor.STATE.BACKGROUND.clone();
					Editor.STATE.BACKGROUNDTEMP.toFront();

					isActive = true;
					figConnector.toFront();
				}
			},
			onmousemove: function (e) {
				var offsetY = $(window).scrollTop();
				var offsetX = $(window).scrollLeft();

				var pos = $("#canvas").position();
				var dX = e.clientX - dx - pos.left + offsetX;
				var dY = e.clientY - dy - pos.top + offsetY;
				dx += dX;
				dy += dY;


				newPath = ["M", inix, iniy, "L", dx, dy].join(",")
				figConnector.translate(dX, dY);
				figLine.attr({
					path: newPath
				});
				figConnector.toFront();
			},
			onmouseup: function () {
				var bbox = figConnector.getBBox();
				var catched = false;
				Editor.STATE.SHAPES.forEach(function (pair) {
					if (!catched && !pair.value.getIsDeleted()) {
						var s = pair.value;
						if (Editor.Geometry.intersectShapes(bbox.x, bbox.y, bbox.width, bbox.height, s.getX(), s.getY(), s.getWidth(), s.getHeight())) {
							if (( (s.getTypeClass() == "resourceConnectable" || s.getTypeClass() == "literal") || 
								(s.getTypeClass() == "vocabIndividual" && impl.getTypeClass() =="vocabIndividual") ) 
								&& (s.getUuid() != impl.getUuid())) {
								var ax = (impl.getX() + impl.getWidth() / 2) + (s.getX() + s.getWidth() / 2 - inix) / 2;
								var ay = (impl.getY() + impl.getHeight() / 2) + (s.getY() + s.getHeight() / 2 - iniy) / 2;
								if (Editor.CONFIG.GRID_SNAP) {
									ax = Math.round(ax / Editor.CONFIG.GRID_SIZE) * Editor.CONFIG.GRID_SIZE;
									ay = Math.round(ay / Editor.CONFIG.GRID_SIZE) * Editor.CONFIG.GRID_SIZE;
								}

								var p;
								var shapeAndConnections;
								var cmd = new JS.Command({
									execute: function () {
										if (this.shape != undefined) {
											this.shape.draw();
											shapeAndConnections.connectionIni.unremove();
											shapeAndConnections.connectionEnd.unremove();
										} else {
											shapeAndConnections = Editor.Util.addProperty(ax, ay, Math.uuid(), impl.getUuid(), s.getUuid());
											this.shape = shapeAndConnections.shape;
											p = this.shape;
										}
									},
									undo: function () {
										this.shape._remove();
										shapeAndConnections.connectionIni.remove();
										shapeAndConnections.connectionEnd.remove();
									},
									stack: Editor.STATE.CMDSTACK
								});

								cmd.name = 'add property';
								cmd.execute();
								Editor.STATE.ISADDSHAPE = true;
								p.showEdit();
								catched = true;
							} else if (impl.getTypeClass() == "vocabProperty" && s.getTypeClass() == "vocabClass") {
								var connection;
								var oldRange = impl.getRange();
								var oldConnection;
								var cmd = new JS.Command({
									execute: function () {
										if (!connection) {
											if (oldRange) {
												Editor.STATE.CONNECTIONS.forEach(function(pair) {
													var c = pair.value;
													if (!c.getIsDeleted()) {
														if (c.getUuidShapeIni() == impl.getUuid() && c.getUuidShapeEnd() == oldRange) {
															oldConnection = c;
														}
													}
												});
												oldConnection.remove();
											}
										connection = Editor.Util.addConnection(impl.getUuid(),s.getUuid());
										impl.setRange(s.getUuid());
									} else {
										connection.unremove();
										if (oldRange) {
											oldConnection.remove();
										}
										impl.setRange(s.getUuid());
									}
								},
								undo: function () {
									connection.remove();
									if (oldRange) {
										oldConnection.unremove();
										impl.setRange(oldRange);
									}
								},
								stack: Editor.STATE.CMDSTACK
							});
							cmd.name = 'add connection';
							cmd.execute();
							catched = true;
						} else if ( (impl.getTypeClass() == "vocabIndividual" && s.getTypeClass() == "vocabClass") || 
						 	    (impl.getTypeClass() == "vocabClass" && s.getTypeClass() == "vocabClass" && s.getUuid() != impl.getUuid()) ||
									(impl.getTypeClass() == "vocabProperty" && s.getTypeClass() == "vocabProperty" && s.getUuid() != impl.getUuid()) ) {
							var connection;
							var cmd = new JS.Command({
								execute: function () {
									if (!connection) {
										connection = Editor.Util.addConnection(impl.getUuid(),s.getUuid());
									} else {
										connection.unremove();
									}
								},
								undo: function () {
									connection.remove();
								},
								stack: Editor.STATE.CMDSTACK
							});
							cmd.name = 'add connection';
							cmd.execute();
							catched = true;
						}
					}
				}
			});
			figLine.remove();
			delete figLine;
			var varX = dx - inix;
			var varY = dy - iniy;
			figConnector.translate(-varX, -varY);
			figConnector.attr(Editor.CONFIG.INVISIBLE_ATTR);
			
			Editor.STATE.BACKGROUNDTEMP.remove();
			delete Editor.STATE.BACKGROUNDTEMP;

			isActive = false;
			Editor.STATE.DRAGGER = undefined;
		},
		translate: function (deltaX, deltaY) {
			figConnector.translate(deltaX, deltaY);
		},
		getIsActive: function () {
			return isActive;
		},
		toFront: function () {
			figConnector.toFront();
		}
	}
}
